package org.robotlegs.base
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	import org.robotlegs.core.IInjector;
	import org.robotlegs.core.IViewMap;

	
public class ViewMap extends ViewMapBase implements IViewMap
{
	public function ViewMap(contextView:DisplayObjectContainer, injector:IInjector)
	{
		super(contextView, injector);

		// mappings - if you can do it with fewer dictionaries you get a prize
		this.mappedPackages = new Array();
		this.mappedTypes = new Dictionary(false);
		this.injectedViews = new Dictionary(true);
	}

	
	
	
	protected var mappedPackages:Array;

	protected var mappedTypes:Dictionary;

	protected var injectedViews:Dictionary;

	
	
	
	//---------------------------------------------------------------------
	// API
	//---------------------------------------------------------------------


	public function mapPackage(packageName:String):void
	{
		if (mappedPackages.indexOf(packageName) == -1)
		{
			mappedPackages.push(packageName);
			viewListenerCount++;
			if (viewListenerCount == 1)
				addListeners();
		}
	}


	public function unmapPackage(packageName:String):void
	{
		var index:int = mappedPackages.indexOf(packageName);
		if (index > -1)
		{
			mappedPackages.splice(index, 1);
			viewListenerCount--;
			if (viewListenerCount == 0)
				removeListeners();
		}
	}

	/**
	 * @inheritDoc
	 */
	public function mapType(type:Class):void
	{
		if (mappedTypes[type])
			return;

		mappedTypes[type] = type;

		viewListenerCount++;
		if (viewListenerCount == 1)
			addListeners();

		// This was a bad idea - causes unexpected eager instantiation of object graph 
		if (contextView && (contextView is type))
			injectInto(contextView);
	}

	/**
	 * @inheritDoc
	 */
	public function unmapType(type:Class):void
	{
		var mapping:Class = mappedTypes[type];
		delete mappedTypes[type];
		if (mapping)
		{
			viewListenerCount--;
			if (viewListenerCount == 0)
				removeListeners();
		}
	}


	public function hasType(type:Class):Boolean
	{
		return (mappedTypes[type] != null);
	}


	public function hasPackage(packageName:String):Boolean
	{
		return mappedPackages.indexOf(packageName) > -1;
	}


	
	
	
	protected override function addListeners():void
	{
		if (contextView && enabled)
			contextView.addEventListener(Event.ADDED_TO_STAGE, onViewAdded, useCapture, 0, true);
	}

	
	protected override function removeListeners():void
	{
		if (contextView)
			contextView.removeEventListener(Event.ADDED_TO_STAGE, onViewAdded, useCapture);
	}


	protected override function onViewAdded(e:Event):void
	{
		var target:DisplayObject = DisplayObject(e.target);
		if (injectedViews[target])
			return;

		for each (var type:Class in mappedTypes)
		{
			if (target is type)
			{
				injectInto(target);
				return;
			}
		}

		var len:int = mappedPackages.length;
		if (len > 0)
		{
			var className:String = getQualifiedClassName(target);
			for (var i:int = 0; i < len; i++)
			{
				var packageName:String = mappedPackages[i];
				if (className.indexOf(packageName) == 0)
				{
					injectInto(target);
					return;
				}
			}
		}
	}

	
	protected function injectInto(target:DisplayObject):void
	{
		injector.injectInto(target);
		injectedViews[target] = true;
	}
}
}
